
#include "mp4_to_h264.h"
#include "rtsp_demo.h"

#define DEBUG(fmt, args...) 	printf(fmt, ##args)
unsigned char g_sps[64] = {0};
unsigned char g_pps[64] = {0};
unsigned int  g_spslen  = 0;
unsigned int  g_ppslen  = 0;

extern rtsp_session_handle g_playback_session;

int getH264Stream(MP4FileHandle mp4Handler, int videoTrackId, int totalSamples, char *saveFileName)
{
	// 调用的接口要传的参数
	uint32_t curFrameIndex = 1; // `MP4ReadSample`函数的参数要求是从1开始，但我们打印帧下标还是从0开始
    uint8_t *pData = NULL;
    uint32_t nSize = 0;
    MP4Timestamp pStartTime;
    MP4Duration pDuration;
    MP4Duration pRenderingOffset;
    bool pIsSyncSample = 0;

	// NALU起始码
    char naluHeader[4] = {0x00, 0x00, 0x00, 0x01};

    // 帧率控制参数
    struct timeval tv_start, tv_current;
    unsigned long time_elapsed = 0;
    const unsigned long frame_interval = 40000; // 40ms (25fps) 的微秒表示

    if(!mp4Handler)
		return -1;

    // 初始化开始时间
    gettimeofday(&tv_start, NULL);

    while(curFrameIndex <= totalSamples)
    {
        // 如果传入MP4ReadSample的视频pData是null，它内部就会new 一个内存
        // 如果传入的是已知的内存区域，则需要保证空间bigger then max frames size.
        MP4ReadSample(mp4Handler, videoTrackId, curFrameIndex, &pData, &nSize, &pStartTime, &pDuration, &pRenderingOffset, &pIsSyncSample);
		// DEBUG("[\033[35mvideo\033[0m] ");

        if(pData && nSize > 4)
		{
			// `MP4ReadSample`函数的参数要求是从1开始，但我们打印帧下标还是从0开始；而大小已经包含了4字节的start code长度
			// DEBUG("frame index: %d\t size: %d\n", curFrameIndex - 1, nSize);

            // 准备推流数据
            RtspServerPushStreamInfo info = {0};
            info.chn = -1;
            info.stream_type = RTSP_SERVER_STREAMING_MAIN;
            info.pts = -1;
			info.frame_type = RTSP_SERVER_FRAME_VIDEO;

            if (pData && nSize > 4) {
                if(pIsSyncSample) {
                    // 对于I帧，需要将SPS、PPS和I帧数据合并
                    // 计算总长度: SPS(4+g_spslen) + PPS(4+g_ppslen) + 帧数据(4+nSize-4)
                    uint32_t totalSize = (4 + g_spslen) + (4 + g_ppslen) + (4 + nSize - 4);
                    uint8_t *combinedData = (uint8_t *)malloc(totalSize);

                    if (combinedData) {
                        uint32_t offset = 0;

                        // 添加SPS
                        memcpy(combinedData + offset, naluHeader, 4);
                        offset += 4;
                        memcpy(combinedData + offset, g_sps, g_spslen);
                        offset += g_spslen;

                        // 添加PPS
                        memcpy(combinedData + offset, naluHeader, 4);
                        offset += 4;
                        memcpy(combinedData + offset, g_pps, g_ppslen);
                        offset += g_ppslen;

                        // 添加I帧数据
                        memcpy(combinedData + offset, naluHeader, 4);
                        offset += 4;
                        memcpy(combinedData + offset, pData + 4, nSize - 4);

                        // 推送合并后的数据
                        info.buff = combinedData;
                        info.size = totalSize;
                    #ifdef RTSP_RECORD
                        RtspServerPushStream(&info);
                    #else
                        rtsp_tx_video(g_playback_session, info.buff, info.size,  info.pts);
                    #endif

                        free(combinedData);
                    }
                } else {
                    // 对于P帧，直接推送帧数据
                    uint8_t *frameData = (uint8_t *)malloc(4 + nSize - 4);
                    if (frameData) {
                        memcpy(frameData, naluHeader, 4);
                        memcpy(frameData + 4, pData + 4, nSize - 4);

                        info.buff = frameData;
                        info.size = 4 + nSize - 4;
                    #ifdef RTSP_RECORD
                        RtspServerPushStream(&info);
                    #else
                        rtsp_tx_video( g_playback_session, info.buff, info.size, info.pts);
                    #endif

                        free(frameData);
                    }
                }
            }
        }

        free(pData);
        pData = NULL;

        curFrameIndex++;

        // 控制帧率为25fps
        gettimeofday(&tv_current, NULL);
        time_elapsed = (tv_current.tv_sec - tv_start.tv_sec) * 1000000 + (tv_current.tv_usec - tv_start.tv_usec);

        // 计算应该的帧间隔
        unsigned long expected_time = (curFrameIndex - 1) * frame_interval;

        // 如果实际用时小于预期时间，则等待
        if (time_elapsed < expected_time) {
            usleep(expected_time - time_elapsed);
        }
    }

    return 0;
}

int getAACStream(MP4FileHandle mp4Handler, int audioTrackId, int totalSamples, char *saveFileName)
{
	// 调用的接口要传的参数
	uint32_t curFrameIndex = 1; // `MP4ReadSample`函数的参数要求是从1开始，但我们打印帧下标还是从0开始
    uint8_t *pData = NULL;
    uint32_t nSize = 0;

    // 帧率控制参数
    struct timeval tv_start, tv_current;
    unsigned long time_elapsed = 0;
    const unsigned long frame_interval = 40000; // 40ms (25fps) 的微秒表示

	if(!mp4Handler)
		return -1;

	// 初始化开始时间
    gettimeofday(&tv_start, NULL);

	while(curFrameIndex <= totalSamples)
	{
		// 如果传入MP4ReadSample的音频pData是null，它内部就会new 一个内存
		// 如果传入的是已知的内存区域，则需要保证空间bigger then max frames size.
		MP4ReadSample(mp4Handler, audioTrackId, curFrameIndex, &pData, &nSize, NULL, NULL, NULL, NULL);

		DEBUG("[\033[36maudio\033[0m] ");

		if(pData && nSize > 0)
		{
			DEBUG("frame index: %d\t size: %d\n", curFrameIndex - 1, nSize);

			// 准备推流数据
            RtspServerPushStreamInfo info = {0};
            info.chn = -1;
            info.stream_type = RTSP_SERVER_STREAMING_MAIN;
            info.frame_type = RTSP_SERVER_FRAME_AUDIO;
            info.pts = -1;
            info.buff = pData;
            info.size = nSize;
            // RtspServerPushStream(&info);
		}

		free(pData);
		pData = NULL;

		curFrameIndex++;

		// 控制帧率为25fps
        gettimeofday(&tv_current, NULL);
        time_elapsed = (tv_current.tv_sec - tv_start.tv_sec) * 1000000 + (tv_current.tv_usec - tv_start.tv_usec);

        // 计算应该的帧间隔
        unsigned long expected_time = (curFrameIndex - 1) * frame_interval;

        // 如果实际用时小于预期时间，则等待
        if (time_elapsed < expected_time) {
            usleep(expected_time - time_elapsed);
        }
	}

	return 0;
}

int streaming_thread_func(void* arg){
    printf("streaming_thread_func\n");

    unpackMp4File(arg, "video.h264", "audio.aac");

    printf("streaming_thread_func over\n");
    return 0;
}

int unpackMp4File(char *mp4FileName, char *videoFileName, char *audioFileName)
{
	MP4FileHandle mp4Handler = 0;
	uint32_t trackCnt = 0;
	int videoTrackId = -1;
	int audioTrackId = -1;
	unsigned int videoSampleCnt = 0;
	unsigned int audioSampleCnt = 0;


	mp4Handler = MP4Read(mp4FileName);
	if (mp4Handler <= 0)
	{
		printf("MP4Read(%s) error!\n", mp4FileName);
		return -1;
	}

	trackCnt = MP4GetNumberOfTracks(mp4Handler, NULL, 0); //获取音视频轨道数
	printf("****************************\n");
	printf("trackCnt: %d\n", trackCnt);

    for (int i = 0; i < trackCnt; i++)
    {
		// 获取trackId，判断获取数据类型: 1-获取视频数据，2-获取音频数据
		MP4TrackId trackId = MP4FindTrackId(mp4Handler, i, NULL, 0);
		const char* trackType = MP4GetTrackType(mp4Handler, trackId);

		if (MP4_IS_VIDEO_TRACK_TYPE(trackType))
		{
			// 不关心，只是打印出来看看
			MP4Duration duration = 0;
			uint32_t timescale = 0;

			videoTrackId = trackId;

			duration = MP4GetTrackDuration(mp4Handler, videoTrackId);
			timescale = MP4GetTrackTimeScale(mp4Handler, videoTrackId);
			videoSampleCnt = MP4GetTrackNumberOfSamples(mp4Handler, videoTrackId);

			printf("video params: \n"
				   " - trackId: %d\n"
				   " - duration: %lu\n"
				   " - timescale: %d\n"
				   " - samples count: %d\n",
				   videoTrackId, duration, timescale, videoSampleCnt);

			// 读取 sps/pps
			uint8_t **seqheader;
			uint32_t *seqheadersize;
			uint8_t **pictheader;
			uint32_t *pictheadersize;

			MP4GetTrackH264SeqPictHeaders(mp4Handler, videoTrackId, &seqheader, &seqheadersize, &pictheader, &pictheadersize);

			// 获取sps
            for (int ix = 0; seqheadersize[ix] != 0; ix++)
            {
				memcpy(g_sps, seqheader[ix], seqheadersize[ix]);
				g_spslen = seqheadersize[ix];
				free(seqheader[ix]);
			}
			free(seqheader);
			free(seqheadersize);

			// 获取pps
			for (int ix = 0; pictheader[ix] != 0; ix++)
			{
				memcpy(g_pps, pictheader[ix], pictheadersize[ix]);
				g_ppslen = pictheadersize[ix];
				free(pictheader[ix]);
			}
			free(pictheader);
			free(pictheadersize);
        }
		else if (MP4_IS_AUDIO_TRACK_TYPE(trackType))
		{
			audioTrackId = trackId;
			audioSampleCnt = MP4GetTrackNumberOfSamples(mp4Handler, audioTrackId);

			printf("audio params: \n"
				   " - trackId: %d\n"
				   " - samples count: %d\n",
				   audioTrackId, audioSampleCnt);
        }
    }
	printf("****************************\n");

    // 解析完了mp4，主要是为了获取sps pps 还有video的trackID
    if(videoTrackId >= 0)
	{
        getH264Stream(mp4Handler, videoTrackId, videoSampleCnt, videoFileName);
    }

	if(audioTrackId >= 0)
	{
        // getAACStream(mp4Handler, audioTrackId, audioSampleCnt, audioFileName);
    }

    // 需要mp4close 否则在嵌入式设备打开mp4上多了会内存泄露挂掉.
    MP4Close(mp4Handler, 0);

    return 0;
}

